//
//  HJWebSocketManager.m
//  KaiChat
//
//  Created by lx on 2023/10/16.
//

#import "HJWebSocketManager.h"
#import <SocketRocket/SocketRocket.h>
#import "HJTimer.h"
#import "HJDataPacketHeader.h"
#import "HJIM.h"

@interface HJWebSocketManager()<SRWebSocketDelegate>

@property (nonatomic, strong) SRWebSocket *webSocket;
@property (nonatomic, copy) NSPointerArray *delegates;
@property (nonatomic, assign) NSInteger sendHeartbeatFailCount;
@property (nonatomic, assign) NSInteger autoReconnectCount;
@property (nonatomic, strong) HJTimer *timer;
@property (nonatomic, assign) HJWebSocketConnectState state;
@property (nonatomic, strong) NSArray *logCmds;
@property (nonatomic, strong) NSMutableData *readData;
@property (nonatomic, assign) BOOL loadOfflineMessage;

@end

@implementation HJWebSocketManager


static HJWebSocketManager *_shareInstance = nil;
+ (instancetype)shareManager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _shareInstance = [[self alloc] init];
    });
    return _shareInstance;
}

- (void)addDelegate:(id<HJWebSocketManagerDelegate>)delegate {
    if ([self.delegates.allObjects containsObject:delegate]) return;
    [self.delegates addPointer:(__bridge void * _Nullable)(delegate)];
}

- (void)removeDelegate:(id<HJWebSocketManagerDelegate>)delegate {
    if ([self.delegates.allObjects containsObject:delegate]) {
        NSUInteger index = [self.delegates.allObjects indexOfObject:delegate];
        [self.delegates removePointerAtIndex:index];
    }
}

- (HJTimer *)timer {
    if (!_timer) {
        _timer = [[HJTimer alloc] init];
    }
    return _timer;
}

- (instancetype)init {
    if (self = [super init]) {
        self.state = HJWebSocketConnectStateConnecting;
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
    }
    return self;
}

- (void)applicationWillEnterForeground {
    [self reconnect];
}

- (void)applicationDidEnterBackground {
    [_timer cancel];
    _webSocket.delegate = nil;
    [_webSocket close];
}

- (void)sendRequestWithUrl:(NSString *)url body:(NSDictionary *)body complete:(void (^__nullable)(NSDictionary * _Nullable data, NSError  * _Nullable error))complete {
    [HJNetworking.shareNetwork POSTBodyJSON:url parameters:body success:^(NSDictionary * _Nonnull responseObject, id  _Nonnull data) {
        !complete ?: complete(data, nil);
    } failure:^(NSError * _Nonnull error) {
        !complete ?: complete(nil, error);
    }];
}

- (void)sendMessageWithDto:(HJMessageDto *)dto complete:(void (^)(NSDictionary * _Nullable, NSError * _Nullable))complete {
    if (!dto.urlPath) return;
    [HJNetworking.shareNetwork POSTBodyJSON:dto.urlPath parameters:dto.mj_keyValues success:^(NSDictionary * _Nonnull responseObject, id  _Nonnull data) {
        !complete ?: complete(data, nil);
    } failure:^(NSError * _Nonnull error) {
        !complete ?: complete(nil, error);
    }];
}

- (void)sendHeartbeat {
    _sendHeartbeatFailCount++;
    HJDataPacketHeader *packetHeader = [[HJDataPacketHeader alloc] initWithBodyData:nil seq:2 operation:HJDataPacketOperationHeartbeat];
    NSData *packetData = HJMakePacketData(packetHeader.data, nil);
    [_webSocket sendData:packetData error:nil];
}

- (BOOL)sendData:(nullable NSData *)data error:(NSError **)error {
    return [_webSocket sendData:data error:error];
}

- (void)userAuthorization {
    NSMutableDictionary *authorizationDict = [NSMutableDictionary dictionary];
    [authorizationDict setValue:@"iOS" forKey:@"platform"];
    [authorizationDict setValue:HJUserInfo.token forKey:@"authorization"];
    [authorizationDict setValue:@(HJUserInfo.userId.integerValue) forKey:@"mid"];
    NSData *bodyData = authorizationDict.mj_JSONData;
    HJDataPacketHeader *packetHeader = [[HJDataPacketHeader alloc] initWithBodyData:bodyData seq:1 operation:HJDataPacketOperationAuthorization];
    NSData *packetData = HJMakePacketData(packetHeader.data, bodyData);
    [_webSocket sendData:packetData error:nil];
}

- (void)connect {
    TJLog(@"%s", __func__);
    if (!HJUserInfo.isLogin) return;
    
    _sendHeartbeatFailCount = 0;
    _autoReconnectCount = 0;
    [_timer cancel];
    
    self.state = HJWebSocketConnectStateConnecting;
    
    _webSocket = [[SRWebSocket alloc] initWithURL:[NSURL URLWithString:@"ws://test-api-ai.ai-chat.ltd/sub"]];
    _webSocket.delegate = self;
    [_webSocket open];
    
}

- (void)reconnect {
    TJLog(@"%s", __func__);
    if (!HJUserInfo.isLogin) return;
    
    [_timer cancel];
    
    _webSocket.delegate = nil;
    [_webSocket close];
    self.state = HJWebSocketConnectStateConnecting;
    
    _webSocket = [[SRWebSocket alloc] initWithURL:[NSURL URLWithString:@"ws://test-api-ai.ai-chat.ltd/sub"]];
    _webSocket.delegate = self;
    [_webSocket open];
    
}

- (void)disconnect {
    TJLog(@"%s", __func__);
    _webSocket.delegate = nil;
    [_webSocket close];
    [_timer cancel];
}

- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
    TJLog(@"webSocket连接成功"); //不能链接成功了就
    self.state = HJWebSocketConnectStateSucceed;
    _readData = [NSMutableData data];
    [self userAuthorization];
}

- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessageWithData:(NSData *)data {
    TJLog(@"didReceiveMessageWithData长度: %ld", data.length);
    if (data) {
        [self.readData appendData:data];
        [self parseData];
    }
}


- (void)parseData {
    while ([self.readData length] >= 16) {
        
        NSRange headerRange = NSMakeRange(0, 16);
        NSData *headerData = [self.readData subdataWithRange:headerRange];
        HJDataPacketHeader *header = [[HJDataPacketHeader alloc] initWithHeaderData:headerData];
        
        //读取头部的值, 对应的包的长度
        uint32_t packageLenght = header.packageLenght;
        if (packageLenght > (uint32_t)[self.readData length]) {// 包体长度 + 包头长度 = 包长度  > 总数据长度，（表示为粘包）
            break;
        }
        
        NSData *payloadData = [self.readData subdataWithRange:NSMakeRange(16, packageLenght - 16)];
        [self.readData replaceBytesInRange:NSMakeRange(0, packageLenght) withBytes:NULL length:0];
        [self didReceiveMessageWithData:payloadData header:header];
    }
    
}

- (void)didReceiveMessageWithData:(NSData *)bodyData header:(HJDataPacketHeader *)header {
    
//    TJLog(@"包头 = %@", header);

    if (header.operation == HJDataPacketOperationReplyHeartbeat) {//授权成功, 发送心跳
        _sendHeartbeatFailCount = 0;
        TJLog(@"心跳在线");
        if (_loadOfflineMessage) {
            _loadOfflineMessage = NO;
            TJLog(@"拉取离线消息");
            [[HJIM shareIM].messageManager loadOfflineMessageCompletion:nil];
        }
        return;
    }
    
    if (header.operation == HJDataPacketOperationReplyAuthorization) {
        TJLog(@"授权成功");
        _autoReconnectCount = 0;
        _loadOfflineMessage = YES;
        __weak typeof(self) weakself = self;
        [self.timer start_SEC:20 ongoing:^{
            [weakself sendHeartbeat];
        }];
        return;
    }
    
    if (header.operation == HJDataPacketOperationSingleMessage || header.operation == HJDataPacketOperationGroupMessage || header.operation == HJDataPacketOperationRetryMessage) {
        NSDictionary *messageDict = bodyData.mj_JSONObject;
        TJLog(@"didReceiveMessageWithData = %@", messageDict);
        if (messageDict) {
            for (id<HJWebSocketManagerDelegate>delegate in self.delegates) {
                if ([delegate respondsToSelector:@selector(webSocket:didReceiveMessage:)]) {
                    [delegate webSocket:self didReceiveMessage:messageDict];
                }
            }
        } else {
            TJLog(@"消息体为空");
        }
    }
}
 

- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
    TJLog(@"%s error = %@", __func__, error);
    if (![self autoReconnect]) {
        self.state = HJWebSocketConnectStateFail;
        for (id<HJWebSocketManagerDelegate>delegate in self.delegates) {
            if ([delegate respondsToSelector:@selector(webSocket:didConnectFail:)]) {
                [delegate webSocket:self didConnectFail:error];
            }
        }
    }
}


//要测下, 没有网络和是连接地址错误是走的哪个方法
//被服务器主动断开
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
    TJLog(@"%s reason = %@, code = %ld", __func__, reason, code);
    if (![self autoReconnect]) {
        self.state = HJWebSocketConnectStateFail;
        for (id<HJWebSocketManagerDelegate>delegate in self.delegates) {
            if ([delegate respondsToSelector:@selector(webSocket:didConnectFail:)]) {
                [delegate webSocket:self didConnectFail:[NSError errorWithCode:code errorReason:reason]];
            }
        }
    }
}


- (BOOL)autoReconnect {
    if (_autoReconnectCount > 3) {
        return NO;
    }
    
    _autoReconnectCount++;
    [self reconnect];
    return YES;
}


- (HJWebSocketConnectState)connectState {
    return _state;
}

- (void)setState:(HJWebSocketConnectState)state {
    _state = state;
    if (state == HJWebSocketConnectStateSucceed) {
        [[NSNotificationCenter defaultCenter] postNotificationName:webSocketConnectStateChangeNotification object:@(state)];
    } else {
        [[NSNotificationCenter defaultCenter] postNotificationName:webSocketConnectStateChangeNotification object:@(self -> _state)];
    }
}

- (NSPointerArray *)delegates {
    if (!_delegates) {
        _delegates = [NSPointerArray weakObjectsPointerArray];
    }
    return _delegates;
}

- (void)tryConnect {
    if (_state == HJWebSocketConnectStateFail) {
        TJLog(@"tryConnect");
        [self reconnect];
    }
}


- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}


@end


